/* 
 * PROJECT: NyARToolkitCS(Extension)
 * --------------------------------------------------------------------------------
 * The NyARToolkitCS is Java edition ARToolKit class library.
 * Copyright (C)2008-2009 Ryo Iizuka
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * For further information please contact.
 *	http://nyatla.jp/nyatoolkit/
 *	<airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
 * 
 */
namespace jp.nyatla.nyartoolkit.cs.core
{


    /**
     * このクラスは、判別法を用いて敷居値を求める機能を提供します。
     * <p>memo:画素数が2048^2に満たない場合は、fixedint(24-8)で計算できます。</p>
     */
    public class NyARHistogramAnalyzer_DiscriminantThreshold : INyARHistogramAnalyzer_Threshold
    {
        private double _score;
        /**
         * この関数は、判別法を用いて敷居値を1個求めます。敷居値の範囲は、i_histogram引数の範囲と同じです。
         * 関数は、thisのプロパティを更新します。
         */
        public int getThreshold(NyARHistogram i_histogram)
        {
            int[] hist = i_histogram.data;
            int n = i_histogram.length;
            int da, sa, db, sb, dt, pt, st;
            int i;
            int th = 0;
            //後で使う
            dt = pt = 0;
            for (i = 0; i < n; i++)
            {
                int h = hist[i];
                dt += h * i;
                pt += h * i * i;//正規化の時に使う定数
            }
            st = i_histogram.total_of_data;
            //Low側(0<=i<=n-2)
            da = dt;
            sa = st;
            //High側(i=n-1)
            db = sb = 0;

            double max = -1;
            double max_mt = 0;
            //各ヒストグラムの分離度を計算する(1<=i<=n-1の範囲で評価)
            for (i = n - 1; i > 0; i--)
            {
                //次のヒストグラムを計算
                int hist_count = hist[i];
                int hist_val = hist_count * i;
                da -= hist_val;
                sa -= hist_count;
                db += hist_val;
                sb += hist_count;

                //クラス間分散を計算
                double dv = (sa + sb);
                double mt = (double)(da + db) / dv;
                double ma = (sa != 0 ? ((double)da / (double)sa) : 0) - mt;
                double mb = (sb != 0 ? ((double)db / (double)sb) : 0) - mt;
                double kai = ((double)(sa * (ma * ma) + sb * (mb * mb))) / dv;
                if (max < kai)
                {
                    max_mt = mt;
                    max = kai;
                    th = i;
                }
                //System.out.println(kai);
            }
            //max_mtを元に正規化
            this._score = max / ((double)(pt + max_mt * max_mt * st - 2 * max_mt * dt) / st);//129,0.8888888888888887
            return th;
        }
        /**
         * 最後に実行した{@link #getThreshold}のスコアを返却します。
         * @return
         * スコア値。範囲は0&lt;=n&lt;=1.0の間です。
         */
        public double getLastScore()
        {
            return this._score;
        }
        /**
         * デバック用関数
         * @param args
         * main関数引数
         */
        public static void main(string[] args)
        {
            NyARHistogram data = new NyARHistogram(256);
            for (int i = 0; i < 256; i++)
            {
                data.data[i] = 128 - i > 0 ? 128 - i : i - 128;
            }
            data.total_of_data = data.getTotal(0, 255);
            NyARHistogramAnalyzer_DiscriminantThreshold an = new NyARHistogramAnalyzer_DiscriminantThreshold();
            int th = an.getThreshold(data);
            //System.out.print(th);
            return;
        }
    }
}
